# -*- coding:utf-8 -*-

__author__='zhaoxp'


import json


class Serializable(object):
    def __init__(self,*args):
        self.args=args

    def serialize(self):
        return json.dumps({'args':self.args})


class Point2D(Serializable):
    def __init__(self,x,y):
        super(Point2D,self).__init__(x,y)
        self.x=x
        self.y=y

    def __repr__(self):
        return 'Point2D(%x,%x)'%(self.x,self.y)


class Deserializable(Serializable):
    @classmethod
    def deserialize(cls,json_data):
        params = json.loads(json_data)
        return cls(*params['args'])


class BetterPoint2D(Deserializable):
    def __init__(self,x,y):
        super(BetterPoint2D,self).__init__(x,y)
        self.x = x
        self.y = y

    def __repr__(self):
        return 'BetterPoint2D(%s,%s)'%(self.x,self.y)


#################################################################################################

class BetterSerializable(object):
    def __init__(self,*args):
        self.args=args

    def serialize(self):
        return json.dumps({'class':self.__class__.__name__,'args':self.args})

registry = {}

def register_class(target_class):
    registry[target_class.__name__] = target_class

def deserialize(json_data):
    data = json.loads(json_data)
    #print('data = %s'%data)
    #print('registry = %s'%registry)
    target_class = registry[data['class']]
    return target_class(*data['args'])


class EvenBetterPoint2D(BetterSerializable):
    def __init__(self,x,y):
        super(EvenBetterPoint2D,self).__init__(x,y)
        self.x=x
        self.y=y

    def __repr__(self):
        return 'EvenBetterPoint2D(%x,%x)'%(self.x,self.y)

register_class(EvenBetterPoint2D)


class Point3D(BetterSerializable):
    def __init__(self,x,y,z):
        super(Point3D,self).__init__(x,y,z)
        self.x,self.y,self.z = x, y, z

#################################################################################################

class Meta(type):
    def __new__(meta,name,bases,class_dict):
        cls = type.__new__(meta,name,bases,class_dict)
        register_class(cls)
        return cls


class RegisteredSerializable(BetterSerializable):
    __metaclass__ = Meta
    pass

class Vector3D(RegisteredSerializable):
    def __init__(self,x,y,z):
        super(Vector3D,self).__init__(x,y,z)
        self.x, self.y, self.z = x, y, z

    def __repr__(self):
        return 'Vector3D(%s,%s,%s)'%(self.x,self.y,self.z)


if __name__=='__main__':
    print('Register Class Existence with Metaclasses')
    p = Point2D(5,3)
    print('Object:     %s'%p)
    print('Serialized: %s'%p.serialize())

    print('-'*30)
    p = BetterPoint2D(6,4)
    print('Before:     %s'%p)
    data = p.serialize()
    print('Serialized: %s'%data)
    data2 = BetterPoint2D.deserialize(data)
    print('After:      %s'%data2)

    print('-'*30)
    p2 = EvenBetterPoint2D(8,7)
    print('Before:     %s'%p2)
    data = p2.serialize()
    print('Serialized: %s'%data)
    p2 = deserialize(data)
    print('After:      %s'%p2)

    print('-'*30)
    p = Point3D(4,6,-3)
    data = p.serialize()
    try:
        deserialize(data)
    except KeyError as ke:
        print('Exception : %s'%ke)

    print('-'*30)
    v = Vector3D(10,-4,7)
    print('Before:     %s'%v)
    data = v.serialize()
    print('Serialized: %s'%data)
    #print('registry = %s'%registry)
    v = deserialize(data)
    print('After:      %s'%v)
